﻿using OpenQA.Selenium;
using OpenQA.Selenium.Firefox;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Linq;
using System.Text.RegularExpressions;

namespace Helpers
{
    public static class SeleniumHelper
    {
        static SeleniumHelper()
        {
            Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
        }
        public static FirefoxWrapper CreateFirefoxDriver(Options.FirefoxConfig config)
        {
            #region FirefoxDriverService
            FirefoxDriverService firefoxDriverService = null;

            //设置gecko驱动路径
            if (config.UseDriver)
            {
                firefoxDriverService = FirefoxDriverService.CreateDefaultService(config.DriverPath, config.DriverName);
            }
            else
                firefoxDriverService = FirefoxDriverService.CreateDefaultService();

            //设置浏览器路径
            if (config.UseBrowser)
                firefoxDriverService.FirefoxBinaryPath = config.BrowserPath;

            firefoxDriverService.HideCommandPromptWindow = config.HideCommandPromptWindow;

            if (config.UseProfile)
            {
                //"C:\\firefox\\Firefox\\firefox.exe" "-marionette" "-marionette-port" "2828"
                firefoxDriverService.BrowserCommunicationPort = 2828;
            }
            #endregion

            #region FirefoxOptions
            FirefoxOptions options = new FirefoxOptions();

            //设置http代理
            if (config.UseProxy)
                options.Proxy = config.proxy;

            //设置用户代理
            if (config.UseRandomUserAgent)
                options.SetPreference("general.useragent.override", config.UserAgent);
            else
                options.SetPreference("general.useragent.override", config.UserAgent);

            //是否显示图片
            if (!config.ShowImage)
                options.SetPreference("permissions.default.image", 2);

            //彻底禁用Web推送功能
            options.SetPreference("dom.webnotifications.enabled", false);
            options.SetPreference("dom.push.enabled", false);
            
            //options.SetPreference("browser.cache.check_doc_frequency", 2);//从不检查缓存
            //options.SetPreference("browser.startup.page", 0);//启动时显示空白
            options.SetPreference("browser.shell.checkDefaultBrowser", false);//关闭检查默认浏览器
            options.SetPreference("browser.search.update", false);//关闭更新
            //options.SetPreference("browser.cache.memory.enable", true);//缓存大小
            //options.SetPreference("browser.cache.memory.capacity", false);//缓存大小


            //设置profile的路径
            FirefoxProfile profile = null;
            if (config.UseProfile)
            {
                options.AddArguments("-profile", config.ProfilePath);
                //profile = new FirefoxProfile(config.ProfilePath);
            }
            else
            {
                profile = new FirefoxProfile(config.ProfilePath);
                //profile = new FirefoxProfile();
                //FirefoxProfileManager firefoxProfile = new FirefoxProfileManager();
                //profile = firefoxProfile.GetProfile("default1");
                //Console.WriteLine(profile.ToBase64String());
                //options.AddArgument("--safe-mode");//安全模式
            }

            if (profile != null)
            {
                profile.DeleteAfterUse = config.AutoDelete;
                options.Profile = profile;
            }

            //是否无头
            if (config.UseHeadless)
            {
                options.AddArgument("--headless");
                //options.AddArgument("--disable-gpu");
            }

            options.LogLevel = config.LogLevel;
            #endregion

            var driver = new FirefoxDriver(firefoxDriverService, options, config.CommandTimeout);
            //var driver = new FirefoxDriver(firefoxDriverService);
            return new FirefoxWrapper(driver, options, firefoxDriverService, config);
        }

        public class FirefoxWrapper : IDisposable
        {
            private int BrowserPid { get; }
            private int DriverServicePid { get; }
            private string ProfilePath { get; }
            public FirefoxDriver Driver { get; }
            public FirefoxOptions Options { get; }
            public FirefoxDriverService Service { get; }
            public Options.FirefoxConfig FirefoxConfig { get; }

            public FirefoxWrapper(FirefoxDriver driver, FirefoxOptions options, FirefoxDriverService service, Options.FirefoxConfig firefoxConfig)
            {
                Driver = driver;
                Options = options;
                Service = service;
                FirefoxConfig = firefoxConfig;
                BrowserPid = int.Parse(Driver.Capabilities.GetCapability("moz:processID").ToString());
                DriverServicePid = Service.ProcessId;
                ProfilePath = Driver.Capabilities.GetCapability("moz:profile").ToString();
            }

            public void Dispose()
            {
                try
                {
                    Driver.Dispose();
                    System.Threading.Thread.Sleep(1000);
                    KillProcess();
                    if (FirefoxConfig.AutoDelete)
                        Delete();
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex);
                }
            }

            private void KillProcess()
            {
                try
                {
                    Process
                        .GetProcesses()
                        .Where(it => (it.Id == BrowserPid || it.Id == DriverServicePid) && it.Id != 0)
                        .ToList()
                        .ForEach(it =>
                        {
                            try
                            {
                                it.Kill();
                            }
                            catch (Exception ex)
                            {
                                ex.Data.Add("pid", it.Id);
                                Console.WriteLine(it.Id + ex.ToString());
                            }
                        });
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex);
                }
            }

            private void Delete()
            {
                try
                {
                    if (Directory.Exists(ProfilePath))
                    {
                        DirectoryInfo subdir = new DirectoryInfo(ProfilePath);
                        subdir.Delete(true);
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex);
                }
            }
        }

        //public static IWebDriver CreatePhantomJSDriver(Options.PhantomJSConfig config)
        //{
        //    var service = PhantomJSDriverService.CreateDefaultService(config.DriverPath);
        //    service.HideCommandPromptWindow = config.HideCommandPromptWindow;
        //    service.LoadImages = config.LoadImages;
        //    service.IgnoreSslErrors = config.IgnoreSslErrors;
        //    service.SslProtocol = config.SslProtocol;
        //    if (config.UseProxy)
        //    {
        //        service.ProxyType = config.ProxyType;
        //        service.Proxy = config.Proxy;
        //        service.ProxyAuthentication = config.ProxyAuthentication;
        //    }

        //    PhantomJSOptions options = new PhantomJSOptions();
        //    options.AddAdditionalCapability("phantomjs.page.settings.userAgent", config.UserAgent);
        //    //options.AddAdditionalCapability("phantomjs.page.settings.Accept", "application/json, */*");
        //    //options.AddAdditionalCapability("phantomjs.page.settings.Accept", "*/*");
        //    IWebDriver driver = new PhantomJSDriver(service, options, config.CommandTimeout);
        //    return driver;
        //}

        public static void Killfirefox()
        {
            var processes = Process.GetProcessesByName("firefox");
            for (int i = 0; i < processes?.Length; i++)
            {
                try
                {
                    processes[i].Kill();
                }
                catch (Exception)
                {
                }
            }
        }

        public static void Killgeckodriver()
        {
            var processes = Process.GetProcessesByName("geckodriver");
            for (int i = 0; i < processes?.Length; i++)
            {
                try
                {
                    processes[i].Kill();
                }
                catch (Exception)
                {
                }
            }
        }
    }
}
